Backend

redis与mysql 的数据一致性如何保证?

如何保证Redis与Mysql的数据一致性?

RedisMySQL

如何保证Redis与Mysql的数据一致性?

常见的方案有这么几种:

  1. 先改数据库,再改缓存
  2. 先改缓存,再改数据库
  3. 先删除缓存,再修改数据库
  4. 先修改数据库,再删缓存
  5. 延迟双删策略,先删除缓存,再修改数据库,再删除缓存
  6. 使用 Binlog 异步更新缓存,监听数据库的 Binlog 变化,通过异步方式更新 Redis 缓存

以上六种实现方式中,前三种一般都不推荐。实际项目开发中用的最多的是第四种和第五种。

这是因为四五的逻辑清晰,且实现简单,并且在绝大多数场景下都能保证数据最终一致性,只会短暂导致数据不一致的场景。但绝大多数场景下,并不要求数据强一致性。而且第六种方案,实现复杂,并且还需要长期对他进行维护,增加额外的维护成本。所以在大多数场景下,第四和第五种方案已经够用了。

先改数据库,再改缓存/ 先改缓存,再改数据库

无论是先修改数据库还是先修改缓存,这两种方案都有一个问题就是:由于可能的网络波动和并发问题,导致请求可能无法顺序执行,请求A和请求B都想要去更新数据,但最后的结果可能是请求A的两步操作中穿插了请求B,或请求B中穿插了请求A。导致数据不一致

先删除缓存再写数据库

他的问题在于:

  1. 请求 A 先对缓存中的数据进行删除操作。
  2. 请求 B 这个时候来执行查询,发现缓存中数据为空,就去数据库进行查询并回写缓存。
  3. 请求 A 进行数据库数据的更新。
  4. 请求 B 已经把从数据库查询到的原始数据回写缓存了。导致了数据不一致

缓存双删(先删除缓存,再写数据库,然后过一段时间再删除缓存)

这个方案为了避免旧数据被回种,等待一段时间后再延迟删除缓存。

也可以使用消息队列、定时任务或者延迟任务等方式去实现延迟删除

先写数据库,再删除缓存

他的问题在于:

  1. 请求B查询缓存为空,然后去查询数据库
  2. 请求A更新数据库,并删除缓存
  3. 请求B将数据库查询的值回写到缓存

其主要原因在于有一个写操作,此时刚好缓存失效,又在同一时刻刚好有一个并发读请求过来,且回写缓存的请求晚于缓存删除,导致数据库与缓存的不一致。

从上面的表述可以知道,这个发生的概率比较低,一般而言业务上都会使用这个方案。

post.comments